#include "iblog_in.h"

static sig_atomic_t		g_SIGTERM_flag = 0 ;

static void sig_set_flag( int sig_no )
{
	if( sig_no == SIGTERM )
	{
		g_SIGTERM_flag = 1 ;
	}
	
	return;
}

static int monitor( struct IblogEnv *p_env )
{
	struct sigaction	act ;
	
	pid_t			pid ;
	int			status ;
	
	int			nret = 0 ;
	
	p_env->listen_session.netaddr.sock = socket( AF_INET , SOCK_STREAM , IPPROTO_TCP ) ;
	if( p_env->listen_session.netaddr.sock == -1 )
	{
		ERRORLOGG( "socket failed , errno[%d]" , errno );
		return -1;
	}
	else
	{
		INFOLOGG( "socket ok[%d]" , p_env->listen_session.netaddr.sock );
	}
	
	SetHttpNonblock( p_env->listen_session.netaddr.sock );
	SetHttpReuseAddr( p_env->listen_session.netaddr.sock );
	SetHttpNodelay( p_env->listen_session.netaddr.sock , 1 );
	
	strncpy( p_env->listen_session.netaddr.ip , p_env->iblog_conf.iblog.server.ip , sizeof(p_env->listen_session.netaddr.ip)-1 );
	p_env->listen_session.netaddr.port = p_env->iblog_conf.iblog.server.port ;
	SETNETADDRESS( p_env->listen_session.netaddr )
	nret = bind( p_env->listen_session.netaddr.sock , (struct sockaddr *) & (p_env->listen_session.netaddr.addr) , sizeof(struct sockaddr) ) ;
	if( nret == -1 )
	{
		ERRORLOGG( "bind[%s:%d][%d] failed , errno[%d]" , p_env->listen_session.netaddr.ip , p_env->listen_session.netaddr.port , p_env->listen_session.netaddr.sock , errno );
		close( p_env->listen_session.netaddr.sock );
		return -1;
	}
	else
	{
		INFOLOGG( "bind[%s:%d][%d] ok" , p_env->listen_session.netaddr.ip , p_env->listen_session.netaddr.port , p_env->listen_session.netaddr.sock );
	}
	
	nret = listen( p_env->listen_session.netaddr.sock , 10240 ) ;
	if( nret == -1 )
	{
		ERRORLOGG( "listen[%s:%d][%d] failed , errno[%d]" , p_env->listen_session.netaddr.ip , p_env->listen_session.netaddr.port , p_env->listen_session.netaddr.sock , errno );
		close( p_env->listen_session.netaddr.sock );
		return -1;
	}
	else
	{
		INFOLOGG( "listen[%s:%d][%d] ok" , p_env->listen_session.netaddr.ip , p_env->listen_session.netaddr.port , p_env->listen_session.netaddr.sock );
	}
	
	act.sa_handler = & sig_set_flag ;
	sigemptyset( & (act.sa_mask) );
	act.sa_flags = 0 ;
	signal( SIGCLD , SIG_DFL );
	signal( SIGCHLD , SIG_DFL );
	signal( SIGPIPE , SIG_IGN );
	sigaction( SIGTERM , & act , NULL );
	
	while(1)
	{
		nret = pipe( p_env->pipe_session.pipe_fds ) ;
		if( nret == -1 )
		{
			ERRORLOGG( "pipe failed , errno[%d]" , errno );
			return -1;
		}
		else
		{
			DEBUGLOGG( "pipe ok[%d][%d]" , p_env->pipe_session.pipe_fds[0] , p_env->pipe_session.pipe_fds[1] );
		}
		
		pid = fork() ;
		if( pid == -1 )
		{
			ERRORLOGG( "fork failed , errno[%d]" , errno );
			return -1;
		}
		else if( pid == 0 )
		{
			INFOLOGG( "child : [%ld] fork [%ld]" , getppid() , getpid() );
			close( p_env->pipe_session.pipe_fds[1] );
			return -worker( p_env );
		}
		else
		{
			INFOLOGG( "parent : [%ld] fork [%ld]" , getpid() , pid );
			close( p_env->pipe_session.pipe_fds[0] );
		}
		
		pid = waitpid( pid , & status , 0 );
		if( pid == -1 )
		{
			if( g_SIGTERM_flag )
				break;
			
			ERRORLOGG( "fork failed , errno[%d]" , errno );
			return -1;
		}
		
		if( WEXITSTATUS(status) == 0 && WIFSIGNALED(status) == 0 && WTERMSIG(status) == 0 )
		{
			INFOLOGG( "waitpid[%d] WEXITSTATUS[%d] WIFSIGNALED[%d] WTERMSIG[%d]" , pid , WEXITSTATUS(status) , WIFSIGNALED(status) , WTERMSIG(status) );
		}
		else
		{
			ERRORLOGG( "waitpid[%d] WEXITSTATUS[%d] WIFSIGNALED[%d] WTERMSIG[%d]" , pid , WEXITSTATUS(status) , WIFSIGNALED(status) , WTERMSIG(status) );
		}
		
		close( p_env->pipe_session.pipe_fds[1] );
		
		sleep(1);
	}
	
	return 0;
}

int _monitor( void *pv )
{
	struct IblogEnv	*p_env = (struct IblogEnv *) pv ;
	
	int		nret = 0 ;
	
	INFOLOGG( "--- iblog.monitor begin --- " );
	
	nret = monitor( p_env ) ;
	
	INFOLOGG( "--- iblog.monitor end --- " );
	
	CleanEnvironment( p_env );
	exit(0);
}

